/**
 *****************************************************************************
 * @file    hal_uart.c
 * @brief    -
 *
 * Copyright (C) RealMega 2019-2020
 *
 *****************************************************************************
*/

#include "co_types.h"
#include "_reg_uart.h"
#include "_reg_clkrst.h"
#include "hal_uart.h"

/****************************************************************
Baudrate\Crystal	32M	        24M	        16M	        12M	
9600	            625/3/1	    625/4/1	    625/6/1	    625/8/1
19200	            625/6/1	    625/8/1	    625/12/1	625/16/1
38400	            625/12/1	625/16/1	625/24/1	625/32/1
57600	            625/18/1	625/24/1	625/36/1	625/48/1
115200	            625/36/1	625/48/1	625/72/1	625/96/1
460800	            625/144/1	625/192/1	625/288/1	625/384/1
921600	            625/288/1	625/384/1	625/576/1	625/192/0
1843200	            625/576/1	625/192/0	625/288/0	625/384/0
******************************************************************/

/*bit 15 was divisor mode, other bits was numerator*/
const uint16_t g_hal_uart_clk_map[4][8] = {
    { (1<<15)|3,   (1<<15)|6,    (1<<15)|12,   (1<<15)|18,   (1<<15)|36,  (1<<15)|144,  (1<<15)|288,  (1<<15)|576 },
    { (1<<15)|4,   (1<<15)|8,    (1<<15)|16,   (1<<15)|24,   (1<<15)|48,  (1<<15)|192,  (1<<15)|384,  (0<<15)|192 },
    { (1<<15)|6,   (1<<15)|12,   (1<<15)|24,   (1<<15)|36,   (1<<15)|72,  (1<<15)|288,  (1<<15)|576,  (0<<15)|288 },
    { (1<<15)|8,   (1<<15)|16,   (1<<15)|32,   (1<<15)|48,   (1<<15)|96,  (1<<15)|384,  (0<<15)|192,  (0<<15)|384 },
   
};

void hal_uart_isr(void)
{

}


void hal_uart_open(const hal_uart_cfg_t* uart_cfg_p)
{
	hwp_uart->cmd_set.b.rx_rts = 0;
	hwp_uart->ctrl.b.dma_mode = 0;
	hwp_uart->ctrl.b.parity_enable = 0;
	hwp_uart->ctrl.b.parity_select = 0;
	hwp_uart->ctrl.b.tx_stop_bits = 0;
	hwp_uart->ctrl.b.data_bits = 1;
	
	hwp_uart->cmd_clr.b.ri = 1;
	hwp_uart->cmd_clr.b.dcr = 1;
	hwp_uart->cmd_clr.b.dsr = 1;
	hwp_uart->cmd_clr.b.tx_break_control = 1;
	hwp_uart->cmd_clr.b.tx_finish_n_wait = 1;
	hwp_uart->cmd_clr.b.rx_cpu_rts = 1;
	
	hwp_uart->cmd_set.b.tx_fifo_reset = 1;
	hwp_uart->cmd_set.b.rx_fifo_reset = 1;

	hwp_uart->irq_mask.v = 0;
	hwp_uart->irq_mask.b.rx_timeout = 1;
	hwp_uart->irq_mask.b.rx_data_available = 1;
	
	hwp_uart->cmd_set.b.rx_rts = 1;//rwhe ?
	hwp_uart->ctrl.b.divisor_mode = 0;//div_4
	hwp_uart->ctrl.b.enable = 1;
}


void hal_uart_close(void)
{
	hwp_uart->ctrl.v = 0;
	hwp_uart->irq_mask.v = 0;
	hwp_uart->irq_cause.v = 0xffff;

	//hwp_sys_ctrl->per_module_en.v &= ~SYS_CTRL_UART0_EN_ENABLE;
}


uint8_t hal_uart_set_baudrate(uint8_t baud_type)
{
    uint8_t     i = 0;
    uint8_t     xtype;
    uint16_t    num;
    

    xtype   = 0;
    num     = g_hal_uart_clk_map[xtype][baud_type];
    
    hwp_clk_rst->uart0_root_cfg.v = CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_DENOM(625) | CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_NUM((num & 0x7FF)) \
                                    | CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_EN | CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_CFG_SET;
    
    hwp_clk_rst->uart0_root_cfg.v |= 1;
    
    while(i<10)i++;

    if(num & BIT15)
    {
        hwp_uart->ctrl.b.divisor_mode = 1;
    }
    else
    {
        hwp_uart->ctrl.b.divisor_mode = 0;
    }
    
    return 0;
}

uint8_t hal_uart_set_baudrate_ex(uint16_t denom, uint16_t num, uint8_t divisor_mode)
{
    uint8_t     i = 0;
    
    if(denom == 0 || denom < num)
    {
        return 1;
    }
    
    hwp_clk_rst->uart0_root_cfg.v = CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_DENOM(denom) | CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_NUM(num) \
                                    | CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_EN | CLKRST_UART0_ROOT_CFG_REG_UART0_ROOT_CLK_CFG_SET;
    
    hwp_clk_rst->uart0_root_cfg.v |= 1;
    
    while(i<10)i++;

    hwp_uart->ctrl.b.divisor_mode = divisor_mode;

    return 0;
}


uint32_t hal_uart_send(const uint8_t* data, uint32_t length)
{
	uint16_t i;

	for (i = 0; i < length; i++)
	{
	    if(hwp_uart->status.b.tx_fifo_space > 0)
	    {
	        hwp_uart->rxtx_buffer.v = data[i];
        }
        else
        {
            break;
        }
    }   

	return i;
}


void hal_uart_set_mask(uint32_t uart_mask)
{
    
}

void hal_uart_dma_init(void)
{
	
}

uint8_t hal_uart_get(void)
{
    //once one byte
    //make sure rx actually Available.(uart_is_rx_fifo_empty)
	return (uint8_t)hwp_uart->rxtx_buffer.v;
}

bool hal_uart_is_rx_fifo_full(void)
{
	return false;
}


bool hal_uart_is_rx_fifo_empty(void)
{
	uint32_t nbAvailable;
	nbAvailable = (((uint32_t)(hwp_uart->status.v) & (UART_STATUS_RX_FIFO_LEVEL_MASK)) >> (0));
	if(0 == nbAvailable)
		return TRUE;
	return FALSE;
}


bool hal_uart_is_tx_fifo_full(void)
{
	return false;
}

bool hal_uart_is_tx_fifo_empty(void)
{
	return false;
}

void hal_uart_set_rts(bool ready)
{   
    //  Control the RTS. 
	if (ready)
	{
		//hwp_uart->cmd_set.v = UART_RX_RTS;
	}
	else
	{
		//hwp_uart->cmd_clr.v = UART_RX_RTS;
	}
}

void hal_uart_irq_set_mask(hal_uart_irq_status_t mask)
{
	union {
		uint32_t reg; // used to write the full reg
		hal_uart_irq_status_t bitfield;
	} u;

	// Uart not open
	if (!((hwp_uart->ctrl.b.enable)))
	{
		return;
	}
	u.bitfield = mask;
	hwp_uart->irq_mask.v = u.reg;
}

void hal_UartFifoFlush(void)
{
	//hwp_uart->cmd_set.v = UART_RX_FIFO_RESET | UART_TX_FIFO_RESET;
}


uint8_t hal_uart_tx_fifo_available(void)
{
	uint8_t txLevel;
	
	if(!(hwp_uart->ctrl.b.enable))
		return 0;
	//  Get level
	txLevel = (((uint32_t)(hwp_uart->status.v) & (UART_STATUS_TX_FIFO_SPACE_MASK)) >> (8));
	return txLevel;
}

bool hal_uart_tx_finished(void)
{
	uint32_t status;
	status = hwp_uart->status.v;
	//  Check if there is no more data to be sent 
	if ((hwp_uart->status.b.tx_active) ||
	(UART_TX_FIFO_SIZE - (((uint32_t)(status) & (UART_STATUS_TX_FIFO_SPACE_MASK)) >> (8)) > 0))
	{
		return FALSE;
	}
	else 
	{
		return TRUE;
	}
	//	return true;
}

char hal_uart_putc(char ch)
{
	while(hwp_uart->status.b.tx_active);
	hwp_uart->rxtx_buffer.v = (uint8_t)ch;
	return ch;
}

void hal_uart_puts(char *s)
{
    while(*s)hal_uart_putc(*s++);
}

uint8_t hal_uart_receive_data(void)
{
  /* Receive Data */
  return (uint8_t)(hwp_uart->rxtx_buffer.v);
}

